
#include <BStyle>
#include <BFont>
#include <BWidget>
#include "member_BTabWidget.h"
#include "member_BAction.h"

using namespace BWE;

member_BTabWidget::member_BTabWidget(BTabWidget* tabWidget)
{
	boss = tabWidget;
	tabAlign = Align_None;
	tabForm = Form_None;
	tabPart = Part_Top;
	tabSpacing = 3;
	beginIndex = 0;
	hoverIndex = -1;
	pressed = false;
	hintTabs = false;
	dirty = true;

	arrow = new BButton(Graph_Arrow_Down, boss);
	arrow->setName("arrow");
	arrow->setCheckable(true);
	arrow->setVisible(false);

	board = new ITabBoard(boss);
	board->setName("board");
	board->arrow = arrow;

	connect(board, Signal_Actived, &member_BTabWidget::slotBoardActived);
	connect(arrow, Signal_Checked, &member_BTabWidget::slotArrowChecked);
}
member_BTabWidget::~member_BTabWidget()
{

}

void member_BTabWidget::slotCloseClicked(BObject* object, const BValue& value)
{
	for (TabItem& item : items)
	{
		if (item.closeButton == object)
		{
			BValue result = item.widget;
			boss->emit(Signal_TabClosing, result);
			if (result != item.widget)
				continue;
			boss->removeTab(item.widget);
			break;
		}
	}
}
void member_BTabWidget::slotTitleChanged(BObject* object, const BValue& value)
{
	auto it = items.find(object);
	if (it.valid())
	{
		it->dirty = true;
		dirty = true;
		boss->fresh();
	}
}
void member_BTabWidget::slotBoardActived(BObject* object, const BValue& value)
{
	if (board->actived() == false)
	{
		arrow->setChecked(false);
	}
}
void member_BTabWidget::slotArrowChecked(BObject* object, const BValue& value)
{
	BButton* arrow = (BButton*)object;
	if (arrow->checked())
	{
		int w = boss->width();

		BRect abRect = board->absoluteRect();
		BRect rootRect = board->root()->rect();
		int maxHeight = rootRect.height() - abRect.y();

		BSize size = board->sizeHint();
		if (size.width() > w)
			size.width() = w;
		if (size.height() > maxHeight)
			size.height() = maxHeight;

		board->setVerticalScrollPolicy(ScrollPolicy_Never);
		board->setHorizontalScrollPolicy(ScrollPolicy_Never);
		board->setPos(tabArea.right() - size.width(), tabArea.bottom());
		board->setSize(size);
		board->popup();
	}
	else
	{
		board->hide();
	}
}

void member_BTabWidget::freshTabs()
{
	if (dirty)
	{
		const BStyle* style = boss->realStyle();
		const BFont* font = boss->font();
		BSize realIconSize = iconSize;
		BSize realButtonSize = buttonSize;
		int rowHeight = bMax(realIconSize.height(), realButtonSize.height());
		if (font)
		{
			if (realIconSize.width() < 1)
				realIconSize.width() = font->size();
			if (realIconSize.height() < 1)
				realIconSize.height() = font->size();
			if (realButtonSize.width() < 1)
				realButtonSize.width() = font->size();
			if (realButtonSize.height() < 1)
				realButtonSize.height() = font->size();
			rowHeight = bMax(realIconSize.height(), realButtonSize.height());
			if (rowHeight < font->size())
				rowHeight = font->size();
		}
		for (auto& item : items)
		{
			if (item.dirty)
			{
				if (style)
					style->translate(item.widget->title(), item.t_title);
				else
					item.t_title.clear();
				if (font)
				{
					if (item.t_title.size())
						item.ia_textSize = font->textSize(item.t_title);
					else
						item.ia_textSize = font->textSize(item.widget->title());
				}
				item.ia_align = tabAlign;
				item.ia_form = tabForm;
				item.ia_spacing = tabSpacing;
				if (item.ia_form == Form_None)
				{
					BIcon* titleIcon = item.widget->titleIcon();
					if (titleIcon)
					{
						item.ia_form = Form_IconText;
						item.ia_imageSize = realIconSize;
					}
				}
				item.rect = item.adjust(BRect());
			}
		}

		tabsSizeHint = realIconSize;
		board->items.clear();
		board->dirty = true;
		board->fresh();

		if (tabPart == Part_Top || tabPart == Part_Bottom)
		{
			int tabHeight = rowHeight;
			for (auto& item : items)
			{
				if (tabHeight < item.rect.height())
					tabHeight = item.rect.height();
			}
			tabHeight += tabMargin.top();
			tabHeight += tabMargin.bottom();
			if (tabPart == Part_Bottom && boss->perch(Part_Bottom) < tabHeight)
				boss->setPerch(Part_Bottom, tabHeight);
			if (tabPart == Part_Top && boss->perch(Part_Top) < tabHeight)
				boss->setPerch(Part_Top, tabHeight);
			if (tabPart == Part_Top)
			{
				tabArea = boss->rect(Part_Top);
				int x = tabArea.left();
				int y = tabArea.top();
				int h = tabArea.height();
				BRect arrowArea = tabArea.align(Align_RightCenter, realButtonSize);
				arrow->setRect(arrowArea);
				for (auto& item : items)
				{
					item.rect.set(x, y, item.ia_hintSize.width() + tabMargin.left() + tabMargin.right(), tabHeight);
					item.adjust(item.rect);
					if (item.closeButton)
					{
						item.rect.setWidth(item.rect.width() + tabHeight);
						BRect closeArea = item.rect;
						closeArea.left() = item.rect.right() - tabHeight;
						item.closeButton->setSize(tabHeight, tabHeight);
						BRect closeRect = closeArea.align(Align_Center, item.closeButton->size());
						item.closeButton->setRect(closeRect);
					}
					if (item.rect.right() > arrowArea.left())
					{
						item.visible = false;
						board->items.append(item);
					}
					else
					{
						item.visible = true;
					}
					if (item.closeButton)
					{
						item.closeButton->setVisible(item.visible);
					}
					x += item.rect.width() + tabSpacing;
					tabsSizeHint.width() += item.rect.width() + tabSpacing;
				}
			}
			if (tabPart == Part_Bottom)
			{
				tabArea = boss->rect(Part_Bottom);
				int x = tabArea.left();
				int y = tabArea.top();
				int h = tabArea.height();
				BRect arrowArea = tabArea.align(Align_RightCenter, realButtonSize);
				arrow->setRect(arrowArea);
				for (auto& item : items)
				{
					item.rect.set(x, y, item.ia_hintSize.width() + tabMargin.left() + tabMargin.right(), tabHeight);
					item.adjust(item.rect);
					if (item.closeButton)
					{
						item.rect.setWidth(item.rect.width() + tabHeight);
						BRect closeArea = item.rect;
						closeArea.left() = item.rect.right() - tabHeight;
						item.closeButton->setSize(tabHeight, tabHeight);
						BRect closeRect = closeArea.align(Align_Center, item.closeButton->size());
						item.closeButton->setRect(closeRect);
					}
					if (item.rect.right() > arrowArea.left())
					{
						item.visible = false;
						board->items.append(item);
					}
					else
					{
						item.visible = true;
					}
					if (item.closeButton)
					{
						item.closeButton->setVisible(item.visible);
					}
					x += item.rect.width() + tabSpacing;
					tabsSizeHint.width() += item.rect.width() + tabSpacing;
				}
			}
		}
		else
		{
			bool closable = false;
			int tabWidth = rowHeight;
			for (auto& item : items)
			{
				if (tabWidth < item.rect.width())
					tabWidth = item.rect.width();
				if (item.closeButton)
					closable = true;
			}
			tabWidth += tabMargin.left();
			tabWidth += tabMargin.right();
			if (closable)
			{
				if (tabPart == Part_Left && boss->perch(Part_Left) < tabWidth + rowHeight)
					boss->setPerch(Part_Left, tabWidth + rowHeight);
				if (tabPart == Part_Right && boss->perch(Part_Right) < tabWidth + rowHeight)
					boss->setPerch(Part_Right, tabWidth + rowHeight);
			}
			else
			{
				if (tabPart == Part_Left && boss->perch(Part_Left) < tabWidth)
					boss->setPerch(Part_Left, tabWidth);
				if (tabPart == Part_Right && boss->perch(Part_Right) < tabWidth)
					boss->setPerch(Part_Right, tabWidth);
			}
			if (tabPart == Part_Left)
			{
				tabArea = boss->rect(Part_Left);
				int x = tabArea.left();
				int y = tabArea.top();
				int h = tabArea.height();
				BRect arrowArea = tabArea.align(Align_RightBottom, realButtonSize);
				arrow->setRect(arrowArea);
				for (auto& item : items)
				{
					item.rect.set(x, y, tabWidth, rowHeight);
					item.adjust(item.rect);
					if (item.rect.bottom() > arrowArea.top())
					{
						item.visible = false;
						board->items.append(item);
					}
					else
					{
						item.visible = true;
					}
					if (item.closeButton)
					{
						BRect closeArea(item.rect.right(), item.rect.top(), realIconSize.width(), realIconSize.height());
						BRect closeRect = closeArea.align(Align_Center, item.closeButton->size());
						item.closeButton->setRect(closeRect);
						item.closeButton->setVisible(item.visible);
					}
					y += item.rect.height() + tabSpacing;
					tabsSizeHint.height() += item.rect.height() + tabSpacing;
				}
			}
			if (tabPart == Part_Right)
			{
				tabArea = boss->rect(Part_Right);
				int x = tabArea.left();
				int y = tabArea.top();
				int h = tabArea.height();
				BRect arrowArea = tabArea.align(Align_RightBottom, realButtonSize);
				arrow->setRect(arrowArea);
				for (auto& item : items)
				{
					item.rect.set(x, y, tabWidth, rowHeight);
					item.adjust(item.rect);
					if (item.rect.bottom() > arrowArea.top())
					{
						item.visible = false;
						board->items.append(item);
					}
					else
					{
						item.visible = true;
					}
					if (item.closeButton)
					{
						BRect closeArea(item.rect.right(), item.rect.top(), realIconSize.width(), realIconSize.height());
						BRect closeRect = closeArea.align(Align_Center, item.closeButton->size());
						item.closeButton->setRect(closeRect);
						item.closeButton->setVisible(item.visible);
					}
					y += item.rect.height() + tabSpacing;
					tabsSizeHint.height() += item.rect.height() + tabSpacing;
				}
			}
		}
		arrow->setVisible(board->items.size());
		dirty = false;
	}
}
void member_BTabWidget::reviseTab()
{

}

int member_BTabWidget::index(BWidget* widget)
{
	for(BList<TabItem>::iterator it = items.begin(); it != items.end(); it++)
	{
		TabItem& item = *it;
		if(item.widget == widget)
		{
			return it.index();
		}
	}
	return -1;
}
BRect member_BTabWidget::rectOf(BWidget* widget)
{
	for(BList<TabItem>::iterator it = items.begin(); it != items.end(); it++)
	{
		TabItem& item = *it;
		if(item.widget == widget)
		{
			return it->rect;
		}
	}
	return BRect();
}
